package cn.tramy.pinxian.wind.handler.dispatch

import cn.tramy.pinxian.wind.handler.DomainMessageWrap
import cn.tramy.pinxian.wind.handler.HandlerInfo
import cn.tramy.pinxian.wind.handler.dispatch.interceptor.DispatchInterceptor
import cn.tramy.pinxian.wind.handler.registry.HandlerRegistry
import org.springframework.transaction.annotation.Transactional

abstract class AbstractCommonDispatcher(private val handlerRegistry: HandlerRegistry) : CommonDispatcher {

    private val groupInterceptors: MutableMap<String, MutableList<DispatchInterceptor>> = mutableMapOf()

    override fun dispatch(message: Any) {
        var realMsg = message
        realMsg = executeBeforeDispatcher(realMsg)


        val payload = guessPayload(realMsg)

        val handlers = handlerRegistry.findHandlers(payload::class.java, groupName())
        if (this.validate(handlers, payload)) {
            handlers.forEach {
                if (it.afterCommit) {
                    DispatchTaskHolder.current().addTask(it, payload)
                } else {
                    it.handle(payload)
                }
            }

            executeAfterDispatch(payload)
        }
    }

    private fun executeAfterDispatch(realMsg: Any) {
        this.groupInterceptors[groupName()]?.forEach { it.afterDispatch(realMsg) }
    }

    private fun executeBeforeDispatcher(realMsg: Any): Any {
        var realMsg1 = realMsg
        this.groupInterceptors[groupName()]?.forEach { realMsg1 = it.beforeDispatch(realMsg1) }
        return realMsg1
    }

    private fun guessPayload(message: Any): Any = (message as? DomainMessageWrap)?.payload ?: message

    override fun addInterceptor(vararg interceptors: DispatchInterceptor) {
        interceptors.forEach {
            this.groupInterceptors.getOrPut(groupName(), { mutableListOf() }).add(it)
        }
    }

    open fun validate(handlers: List<HandlerInfo<out Any>>, message: Any): Boolean = true
}